///////////////////////////////////////////////////////////////////////////////
//	FILENAME:	eTLink.m 
//	SUMMARY:	Implementation of link buttons in eText documents
//	SUPERCLASS:	Object:eTImage
//	INTERFACE:	None
//	PROTOCOLS:	<Annotation,HTMDSupport,ASCIISupport,LaTeXSupport,Tool,
//				InspectableTarget>
//	AUTHOR:		Rohit Khare
//	COPYRIGHT:	(c) 1994 California Institure of Technology, eText Project
///////////////////////////////////////////////////////////////////////////////
//	DESCRIPTION
//		Does its job by holding doc/anchorIDs and yelling at NXApp.
///////////////////////////////////////////////////////////////////////////////
//	HISTORY
//	10/30/94:	Modified to support <InspectableTarget>
//	07/21/94:	Revamped for PR1 and eTImage[Component] support
//	07/09/94:	URLRep added by RK and TRZ (Removed 7/21)
//	07/07/94:	Rewritten as subclass of imageAnnotation
//	07/03/94:	Added eTLinkUI integration for image-links.
//  06/17/94:   HTMDSupport added. RK and TRZ
//	02/04/94:	Created. First actual implementation.
///////////////////////////////////////////////////////////////////////////////

#import "eTLink.h"
#define _eTLinkVERSION	10

@implementation eTLink
//	long	anchorID;
//	long	docID;
//	etfLink	theLink;
//	NXAtom	URLRep;

+ toolAwake:theApp
{
	[theApp   registerAnnotation: [eTLink class] 
							name: "eTLink"
					RTFDirective: "eTLink"
					   menuLabel: NULL
						 menuKey: '\0'
						menuIcon: (NXImage *) nil];
	[theApp registerType:NXCreateFileContentsPboardType("etfd") for:[eTLink class]];
	[theApp registerType:NXCreateFileContentsPboardType("etfLink") for:[eTLink class]];
	return self;
}

- init
{
	[super init];
	
	docID = anchorID = 0;
	theLink.docID = theLink.anchorID = theLink.docTitle = theLink.anchorTitle 
		= NXUniqueString("");
	[self setImageComponent:[eTImageComponent newImageNamed:"NXLinkButton"]];
	[self setAltImageComponent:[eTImageComponent newImageNamed:"NXLinkButtonH"]];
	[self setDraggable:YES];
	return self;
}

- free 
{
	return self = [super free];
}
- setImageComponent:newImageComponent
{
	const char *name;
	
	name = [[newImageComponent theImage] name];
	if (name && !strcmp(name,"NXLinkButton"))
		usesButtonStyle = NO;
	else
		usesButtonStyle = YES;
	return [super setImageComponent:newImageComponent];
}
- initFromPboard:thePB inDoc:theDoc linked:(BOOL) linked
{
	NXAtom 	types[5];
	char	*data;
	int		len;

	[super	initFromPboard:thePB inDoc:theDoc linked: linked];
	[self init];
	types[0] = NXCreateFileContentsPboardType("etfLink");
	types[1] = NXCreateFileContentsPboardType("etfd");
	types[2] = NXCreateFileContentsPboardType(ANY_TYPE);
	types[3] = NXFilenamePboardType;
	types[4] = [thePB findAvailableTypeFrom:types num:4];

	if (!types[4]) return self;
	if (types[4]) {
		[thePB readType:NXFilenamePboardType data:&data length:&len];
		if (index(data,'\t')) *(index(data,'\t'))=0;
		[self initFromFile:data];
		[thePB deallocatePasteboardData:data length:len];
	} else {
		NXLogError("%s got fcontents without fnamepboard! %s instead.",
					[[self class] name], types[4]);
	}
	return self;
}

- initFromFile: (const char *) theFile
{
	id	theTable;

	[self init];
	if (!strcmp("etfLink", rindex(theFile, '.')+1)) {
		theTable = [[NXStringTable alloc] init];
		if ([theTable readFromFile:theFile]) {
			sscanf([theTable valueForStringKey:DOCID], "%x", &docID);
			sscanf([theTable valueForStringKey:ANCHORID], 
						"%x", &anchorID);
			theLink.docID = NXUniqueString([theTable valueForStringKey:DOCID]);
			theLink.anchorID = NXUniqueString([theTable valueForStringKey:ANCHORID]);
			theLink.docTitle = NXUniqueString([theTable valueForStringKey:DOCTITLE]);
			theLink.anchorTitle = NXUniqueString([theTable valueForStringKey:ANCHORTITLE]);
		}
		theTable = [[theTable empty] free]; // free even if read from file failed
	} else if (!strcmp(ETFD_EXT, rindex(theFile, '.')+1)) {
		// find a docID for this file, stash it away
		theTable = [[[eTDocInfo alloc] init] readComponentFromPath:theFile];
		if (theTable){
			docID = [theTable docID];
			anchorID = 0;
			theLink.docID = NXUniqueString([theTable docIDStr]);
			theLink.anchorID = NXUniqueString("0");	
			theLink.anchorTitle = theLink.docTitle = NXUniqueString([theTable title]);
			theTable = [theTable free];
		}
	} else { 
		NXLogError("eTLink asked to init from:%s; cannot.", theFile);
	}
	return self;
}
		
- readRichText:(NXStream *)stream forView:view 
{
	int i;
	char buf[MAXPATHLEN];
	
	NXScanf(stream, "%d ", &i);
	if (i != _eTLinkVERSION) {
		// bad version block.
		NXLogError("eTLink found unparseable version %d at position %d",
					i, NXTell(stream));
		return nil;
	}

	NXScanf(stream, "%s ", buf);
	theLink.docID = NXUniqueString(buf);
	sscanf(theLink.docID, "%x", &docID);

	NXScanf(stream, "%s", buf);
	theLink.anchorID = NXUniqueString(buf);
	sscanf(theLink.anchorID, "%x", &anchorID);

	NXScanf(stream, "%d", &i); NXGetc(stream); //space-eater
	if (i) NXRead(stream, buf, i);
	buf[i] = 0;
	theLink.docTitle = NXUniqueString(buf);

	NXScanf(stream, "%d", &i); NXGetc(stream); //space-eater
	if (i) NXRead(stream, buf, i);
	buf[i] = 0;
	theLink.anchorTitle = NXUniqueString(buf);
	
	NXGetc(stream); // extra space char.
	[super readRichText:stream forView:view];
	return self;
}

- writeRichText:(NXStream *)stream forView:view
{
	id dI=nil;
	
	// maintain docID-docTitle consistency
	dI = [eTDocInfo findDocInfo:docID];
	if (dI) theLink.docTitle= NXUniqueString([dI docTitle]);
	NXPrintf(stream, "%d %s %s %d %s %d %s ", _eTLinkVERSION,
				theLink.docID, theLink.anchorID, 
				strlen(theLink.docTitle), theLink.docTitle,
				strlen(theLink.anchorTitle), theLink.anchorTitle);
	[super writeRichText:stream forView:view];
	return self;
}

- writeASCIIRef:(NXStream *)stream forView:view
{
	if(*theLink.docID) {
		if(theLink.anchorID && anchorID)
			NXPrintf(stream, "See %y in %y [%s in %s]\n\t", theLink.anchorTitle, theLink.docTitle, theLink.anchorID, theLink.docID);
		else
			NXPrintf(stream, "See %y [%s]\n\t", theLink.docTitle, theLink.docID);
	} 
	[super writeASCIIRef:stream forView:view];
	return self;
}

- writeLaTeX:(NXStream*)stream forView:view
{	
	[super writeLaTeX:stream forView:view];
	if(*theLink.docID) {
		if(theLink.anchorID && anchorID)
			NXPrintf(stream, "\n\\footnote{See %w in %w [%w in %w]}\n", theLink.anchorTitle, theLink.docTitle, theLink.anchorID, theLink.docID);
		else
			NXPrintf(stream, "\n\\footnote{See %w [%w]}\n", theLink.docTitle, theLink.docID);
	} 
	return self;
}

- writeHTML:(NXStream *)stream forView:view
{ 
	char tmp[MAXPATHLEN];
	
	id theDocInfo = [eTDocInfo findDocInfo:docID];
	if(!theDocInfo) return self;
	
	if(*theLink.docID) {
		strcpy(tmp, [theDocInfo docPath]);
		*rindex(tmp,'.')=0;
		NXPrintf(stream,"<A HREF=\"../%V."HTMD_EXT"/"HTML_INDEX,rindex(tmp,'/')+1);
		if(anchorID) NXPrintf(stream,"#%s", theLink.anchorID);
		NXPrintf(stream, "\">");
//		if (theLink.anchorTitle && *theLink.anchorTitle) {
//			NXPrintf(stream,"\">&lt;%v&gt;", theLink.anchorTitle);

		[super writeHTML:stream forView:view];
		NXPrintf(stream,"</A>");

//		}
//		else 
//			NXPrintf(stream,"\">&lt;Click Here&gt;</A>");
	}
	return self;
}
#define NXLINK "NXLinkButton"
#define NXLINK_GIF NXLINK".gif"
- writeComponentToPath:(NXAtom)path inFormat:(int) theFormat
{
	const char *name;
	
	if(!etDoc)	NXLogError("etDoc is nil at %s %u",__FILE__,__LINE__);
	name = [[imageComponent theImage] name];
	if ((theFormat == HTMD_FMT) && name && !strcmp(name,NXLINK)) {
		char cmd[2*MAXPATHLEN];

		sprintf(cmd,"%s/"NXLINK_GIF, [[NXBundle mainBundle] directory]);
		if (!access(cmd, F_OK|R_OK)) {
		  sprintf(cmd,"cp -rp \"%s/"NXLINK_GIF"\" \"%s/"NXLINK_GIF"\"", 
				 [[NXBundle mainBundle] directory], path);
		  system(cmd);
		  [etDoc registerComponent:NXLINK_GIF];
		} else {
			[super writeComponentToPath:path inFormat:theFormat];
		}
	} else
		[super writeComponentToPath:path inFormat:theFormat];
	return self;
}

- doubleClick2:sender
{
	if (docID && [eTDocInfo findDocInfo:docID]) {
		[[NXApp etApp] openID:docID];
		[[[objc_lookUpClass("eTBookmarkBinder") new] bookmarkForID:anchorID] highlight:sender];
	} else {
		NXRunAlertPanel("eTLink", "Could not locate docID %x","OK", NULL, NULL,docID);
	}
	return self;
}

- doubleClick:(NXEvent *) e
{
	[self perform:@selector(doubleClick2:) with:self afterDelay:0 
		cancelPrevious:YES];
	return self;
}

- inspect:(NXEvent *) e
{
	[[NXApp inspector] inspect:self];
	return self;
}
- (id <Inspectable>) inspectableDelegate {
	return [[eTLinkUI new] setAnnotation:self]; }

- (NXAtom)anchorTitle 
	{return ((theLink.anchorTitle) ? theLink.anchorTitle : "");}
- (NXAtom)anchorID
	{return ((theLink.anchorID) ? theLink.anchorID : "");}
- (NXAtom)docTitle
	{return ((theLink.docTitle) ? theLink.docTitle : "");}
- (NXAtom)docID
	{return ((theLink.docID) ? theLink.docID : "");}

- drag: (Pasteboard *)draggingPboard image:(NXImage **)proxyImage
{
	id 		theTable;
	char	filename[MAXPATHLEN];
	
	theTable = [[NXStringTable alloc] init];
	[theTable insertKey:DOCID 
		value: NXCopyStringBuffer(theLink.docID)];
	[theTable insertKey:ANCHORID
		value: NXCopyStringBuffer(theLink.anchorID)];
	[theTable insertKey:DOCTITLE value:
		NXCopyStringBuffer(theLink.docTitle)];
	[theTable insertKey:ANCHORTITLE value: 
		NXCopyStringBuffer(theLink.anchorTitle)];
	sprintf(filename, "/tmp/%s.etfLink", theLink.anchorTitle);
	[theTable writeToFile:filename];
	theTable = [[theTable empty] free];

	[draggingPboard declareTypes:&NXFilenamePboardType num:1 owner:nil];
	[draggingPboard writeType: NXFilenamePboardType data: filename
					length: strlen(filename)];
	*proxyImage = [[eTImageComponent newImageNamed:"NXLinkButton"] theImage];
	return self;
}
@end